package indi.kider.server.bill.service;

import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import indi.kider.common.constant.*;
import indi.kider.common.model.apabus.Rent;
import indi.kider.common.model.bill.*;
import indi.kider.common.model.employee.Tenant;
import indi.kider.common.model.meter.MeterReading;
import indi.kider.common.util.MathUtil;
import indi.kider.server.bill.mapper.BillCountByTypeMapper;
import indi.kider.server.bill.mapper.BillMapper;
import indi.kider.server.bill.mapper.BillMonthReportMapper;
import indi.kider.server.bill.model.BalanceCycle;
import indi.kider.server.bill.service.related.HumanResourcesService;
import indi.kider.server.bill.service.related.MeterClientService;
import indi.kider.server.bill.service.related.RentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import pers.vankid.common.constant.DateTime;
import pers.vankid.common.model.base.CommonResponse;
import pers.vankid.common.utils.download.FileDownUtil;
import pers.vankid.common.utils.excel.ExcelExport;
import pers.vankid.common.utils.excel.ExcelUtil;
import pers.vankid.common.utils.page.PageRequest;
import pers.vankid.common.utils.page.PageResponse;
import pers.vankid.common.utils.page.PageUtil;
import tk.mybatis.mapper.entity.Example;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * Created by shixj on 2018/5/4.
 */
@Slf4j
@Service
public class BillServiceImpl implements BillService {
    @Autowired
    private BillMapper billMapper;
    @Autowired
    private BillCountByTypeMapper billCountByTypeMapper;
    @Autowired
    private BillMonthReportMapper billMonthReportMapper;
    @Autowired
    private BalanceTaskService balanceTaskService;
    @Autowired
    private MeterClientService meterClientService;
    @Autowired
    private RentService rentService;
    @Autowired
    private ReadingService readingService;
    @Autowired
    private HumanResourcesService humanResourcesService;

    /**
     * 结算 （后台自动结算专用）
     *
     * @return
     */
    @Override
    @Transactional
    public void balance() {
        BalanceTask query = new BalanceTask();
        query.setBalanceDate(DateTime.SHORT_DATE.format(new Date()));
        query.setStatus(StatusCons.VALID);
        for (BalanceTask balanceTask : balanceTaskService.query(query)) {
                try {
                    balance(balanceTask, false);
                }catch (Exception e){
                    e.printStackTrace();
                    balanceTask.setErrorMsg("数据异常:"+e.getMessage());
                    balanceTask.setStatus(StatusCons.ERROR);
                    balanceTaskService.update(balanceTask);
                }
        }
    }

    /**
     * 结算水
     * 结算电
     * 结算租金等
     *
     * @param balanceTask
     * @return
     */
    @Override
    @Transactional
    public Bill balance(BalanceTask balanceTask, Boolean isEnd) {
        Integer type = balanceTask.getType();
        Bill bill;
        if (type.equals(BillTypeCons.POWER) || type.equals(BillTypeCons.WATER))
            bill = balanceWaterOrPower(balanceTask, isEnd);
        else if (type.equals(BillTypeCons.NET)) {
            bill = balanceNet(balanceTask, isEnd);
        } else if (type.equals(BillTypeCons.ESTATE)) {
            bill = balanceEstate(balanceTask, isEnd);
        } else if (type.equals(BillTypeCons.W_SHARE)) {
            bill = balanceShare(balanceTask, isEnd);
        } else bill = balanceRental(balanceTask, isEnd);
        balanceTaskService.update(balanceTask);
        return bill;
    }

    /**
     * 押金退还冲账
     * @param rentId
     * @return
     */
    @Override
    @Transactional
    public Bill backDeposit(Long rentId) {
        Bill query = new Bill();
        query.setBillType(BillTypeCons.DEPOSIT);
        query.setBillAttribution(rentId);
        query.setRefund(StatusCons.VALID);
        Bill bill = billMapper.selectOne(query);
        if (bill != null) {
            bill.setId(null);
            bill.setTotal(-1 * bill.getTotal());
            bill.setPayState(PayStateCons.UNPAYED);
            bill.setBillTime(new Date());
            bill.setRemark("退还押金");
            bill.setState(StatusCons.VALID);
            bill.setRefund(StatusCons.HISTORY);
            billMapper.insert(bill);
        }
        return bill;
    }
    /**
     * 结算租金
     *
     * @param balanceTask
     * @return
     */
    @Override
    @Transactional
    public Bill balanceRental(BalanceTask balanceTask, Boolean isEnd) {
        boolean isError=false;
        String msg="";
        try {
            Bill bill = init(balanceTask);
            Integer cycle = balanceTask.getBalanceCycle();
            if (cycle.equals(SetLeaseCons.MONTH))
                bill.setTotal(balanceTask.getPrice());
            else if (cycle.equals(SetLeaseCons.QUARTER))
                bill.setTotal(balanceTask.getPrice() * 3);
            else if (cycle.equals(SetLeaseCons.HALF_YERA))
                bill.setTotal(balanceTask.getPrice() * 6);
            else if (cycle.equals(SetLeaseCons.YERA))
                bill.setTotal(balanceTask.getPrice() * 12);
            BalanceCycle balanceCycle = balanceTaskService.getBalanceCycle(balanceTask);
            bill.setTotal(bill.getTotal() * balanceCycle.getActualDays() / balanceCycle.getExceptDays());
            saveBill(bill);
            resolveTask(balanceTask, isEnd);
            return bill;
        } catch (Exception e) {
            isError=true;
            msg=e.getMessage();
        }finally {
            if(isError)
                resolveErrorTask(balanceTask, msg);
        }
        return null;
    }

    /**
     * 结算完成处理任务
     *
     * @param task
     * @param isEnd
     */
    private void resolveTask(BalanceTask task, Boolean isEnd) {
        if (isEnd)
            task.setStatus(StatusCons.VALID);
        else {
            task.setStatus(StatusCons.HISTORY);
            balanceTaskService.saveSufTask(task);
        }
    }

    /**
     * 结算完成处理任务
     *
     * @param task
     * @param errorMsg
     */
    private void resolveErrorTask(BalanceTask task, String errorMsg) {
        task.setStatus(StatusCons.ERROR);
        task.setErrorMsg(BillTypeCons.MAP.get(task.getType()) + "结算异常:【" + errorMsg + "】");
    }

    /**
     * 结算网费
     *
     * @param balanceTask
     * @return
     */
    @Override
    @Transactional
    public Bill balanceNet(BalanceTask balanceTask, Boolean isEnd) {
        try {
            Bill bill = init(balanceTask);
            bill.setBillType(BillTypeCons.NET);
            bill.setTotal(balanceTask.getPrice());
            saveBill(bill);
            resolveTask(balanceTask, isEnd);
            return bill;
        } catch (Exception e) {
            resolveErrorTask(balanceTask, e.getMessage());
        }
        return null;
    }

    /**
     * 结算公摊
     *
     * @param balanceTask
     * @return
     */
    @Override
    public Bill balanceShare(BalanceTask balanceTask, Boolean isEnd) {
        return null;
    }

    /**
     * 结算物业
     *
     * @param balanceTask
     * @return
     */
    @Override
    public Bill balanceEstate(BalanceTask balanceTask, Boolean isEnd) {
        try {
            Bill bill = init(balanceTask);
            bill.setBillType(BillTypeCons.ESTATE);
            bill.setTotal(balanceTask.getPrice());
            saveBill(bill);
            resolveTask(balanceTask, isEnd);
            return bill;
        } catch (Exception e) {
            resolveErrorTask(balanceTask, e.getMessage());
        }
        return null;
    }

    /**
     * 结算水、电
     *
     * @param balanceTask
     * @return
     */
    @Value("${bill.share.radio}")
    private double ratio;

    @Override
    @Transactional
    public Bill balanceWaterOrPower(BalanceTask balanceTask, Boolean isEnd) {
        boolean isError=false;
        String msg="";
        try {
            BalanceTask preTask=balanceTaskService.getPreTask(balanceTask);
            BalanceCycle balanceCycle = balanceTaskService.getBalanceCycle(balanceTask);
            try {
                Rent rent = rentService.getRentById(balanceTask.getBillAttribution()).getData();
                Long houseId;
                if (rent == null) houseId = balanceTask.getHouseId();
                else houseId = rent.getHousesId();
                MeterReading meterReadingQuery = new MeterReading();
                meterReadingQuery.setType(balanceTask.getType());
                meterReadingQuery.setRoomId(houseId);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(balanceCycle.getActualBalanceEndTime());
                calendar.add(Calendar.DATE, -1);

                meterReadingQuery.setDataDate(calendar.getTime());
                meterReadingQuery.setDataDateStart(balanceCycle.getActualBalanceStartTime());
                calendar.setTime(balanceCycle.getActualBalanceEndTime());
                calendar.add(Calendar.DATE, -1);
                meterReadingQuery.setDataDateEnd(calendar.getTime());
                CommonResponse<MeterReading> commonResponse = meterClientService.getDayReading(meterReadingQuery);
                if (commonResponse.doSuccess()) {
                    readingService.saveReadingByClient(commonResponse.getData(), balanceTask.getBillAttribution());
                }else throw new Exception(commonResponse.getMsg());
            } catch (Exception e) {
                throw new Exception("抄读异常:" + e.getMessage());
            }
            BalanceTask q=new BalanceTask();
            q.setId(balanceTask.getId());
            balanceTask=balanceTaskService.queryOne(q);
            Bill bill = init(balanceTask);
            BigDecimal price;
            try {
                price = new BigDecimal(balanceTask.getPrice());
            } catch (Exception r) {
                throw new Exception("价格不合法，价格：" + balanceTask.getPrice());
            }
            BigDecimal absoluteNumber = new BigDecimal(balanceTask.getReading());
            BigDecimal total = absoluteNumber.multiply(price);
            bill.setBillType(balanceTask.getType());
            bill.setAbsoluteNumber(absoluteNumber.abs().floatValue());
            bill.setTotal(total.floatValue());
            bill.setLastRead(0f);
            bill.setLastReadTime(preTask.getReadingTime());
            bill.setThisRead(balanceTask.getReading());
            bill.setThisReadTime(balanceTask.getReadingTime());
            saveBill(bill);
            resolveTask(balanceTask, isEnd);
            return bill;
        } catch (Exception e) {
            isError=true;
            msg=e.getMessage();
        }finally {
            if(isError)
                resolveErrorTask(balanceTask,msg);
        }
        return null;
    }

    /**
     * 新增或更新账单
     *
     * @param bill
     * @return
     */
    private Bill saveBill(Bill bill) {
        if (bill.getId() == null || bill.getId() <= 0)
            billMapper.insert(bill);
        else billMapper.updateByPrimaryKeySelective(bill);
        return bill;
    }

    private Bill init(BalanceTask balanceTask) {
        Bill query = new Bill();
        query.setTaskId(balanceTask.getId());
        Bill bill = billMapper.selectOne(query);
        if (bill == null) bill = query;
        bill.setPrice(balanceTask.getPrice());
        bill.setBillTime(new Date());
        bill.setState(BillClientStateCons.VALID);
        bill.setBillAttribution(balanceTask.getBillAttribution());
        bill.setTaskId(balanceTask.getId());
        bill.setPayState(PayStateCons.UNPAYED);
        bill.setBillType(balanceTask.getType());
        bill.setRefund(StatusCons.VALID);
        return bill;
    }


    @Override
    public List<Bill> query(Bill bill) {
        return billMapper.select(bill);
    }

    @Override
    public PageResponse<List<Bill>> query(PageRequest<Bill> request) {
        Bill query = request.getQuery();
        PageUtil.start(request);
        return PageUtil.getPageResponse(billMapper.select(query));
    }

    @Override
    public Bill queryOne(Long billId) {
        return billMapper.selectByPrimaryKey(billId);
    }

    /**
     * 更新支付状态
     *
     * @param billPay
     * @return
     */
    @Override
    @Transactional
    public void updatePayStatus(BillPay billPay) {
        billPay.getBillIds().stream().forEach(billId -> {
            Bill bill = new Bill();
            bill.setPayState(billPay.getPayState());
            bill.setPaySerial(billPay.getPaySerial());
            bill.setPayTime(billPay.getPayTime() == null ? new Date() : billPay.getPayTime());
            bill.setPayType(billPay.getPayType() == null ? PayTypeCons.OUTLINE : billPay.getPayType());
            bill.setId(billId);
            if (billPay.getTenantId() != null && billPay.getTenantId() > 0) {
                bill.setPayTenantId(billPay.getTenantId());
                Tenant tenant = humanResourcesService.getTenantById(billPay.getTenantId()).getData();
                bill.setPayTenantName(tenant.getName());
                bill.setPayTenantTel(tenant.getPhone());
            }
            billMapper.updateByPrimaryKeySelective(bill);
        });
    }

    /**
     * 根据租房信息查询租房信息和账单
     *
     * @param request
     * @return
     */
    @Override
    public PageResponse<RentBill> queryRentBill(PageRequest<RentBill> request) {
        RentBill query = request.getQuery();
        PageUtil.start(request);
        return PageUtil.getPageResponse(billMapper.getRentBill(query));
    }
    /**
     * 按房间
     *
     * @param request
     * @return
     */
    @Override
    public PageResponse<RentBill> queryRentBillByHouse(PageRequest<RentBill> request) {
        RentBill query = request.getQuery();
        PageUtil.start(request);
        return PageUtil.getPageResponse(billMapper.getRentBillByHouse(query));
    }
    /**
     * 按租客
     *
     * @param request
     * @return
     */
    @Override
    public PageResponse<RentBill> queryRentBillByTenant(PageRequest<RentBill> request) {
        RentBill query = request.getQuery();
        PageUtil.start(request);
        return PageUtil.getPageResponse(billMapper.getRentBillByTenant(query));
    }
    /**
     * 查账单明细
     *
     * @param request
     * @return
     */
    @Override
    public PageResponse<RentBill> queryDayBillByRentId(PageRequest<RentBill> request) {
        RentBill query = request.getQuery();
        PageUtil.start(request);
        return PageUtil.getPageResponse(billMapper.queryDayBillByRentId(query));
    }

    /**
     * 查账单总金额
     * @param request
     * @return
     */
    public  RentBill queryDayBillSumByRentId(RentBill request) {
        return billMapper.queryDayBillSumByRentId(request);
    }

    /**
     * 根据租房信息查询租房信息和账单
     * 导出
     *
     * @param rentBill
     * @return
     */
    @Override
    public ResponseEntity<InputStreamResource> exportRentBill(RentBill rentBill) throws IOException {
        List<RentBill> rentBillList = billMapper.getRentBill(rentBill);
        Map<String, String> colums;
        if(rentBill.getBillType()!=null&&(rentBill.getBillType().equals(BillTypeCons.WATER)||rentBill.getBillType().equals(BillTypeCons.POWER)))
            colums = new ImmutableMap.Builder<String, String>().
                            put("community", "公寓名").
                            put("address", "公寓地址").
                            put("houseNumb", "房间号").
                            put("tenantName", "租客").
                            put("tenantTel", "租客电话").
                            put("billType", "账单类型").
                            put("billTime", "账单时间").
                            put("payState", "支付状态").
                            put("payTime", "支付时间").
                            put("total", "总额").
                            put("paySerial", "支付流水号").
                            put("thisRead", "本次读数").
                            put("thisReadTime", "本次抄读时间").
                            put("lastRead", "上次读数").
                            put("lastReadTime", "上次抄读时间").
                            put("remark", "备注")
                            .build();
            else
        colums =
                new ImmutableMap.Builder<String, String>().
                        put("community", "公寓名").
                        put("address", "公寓地址").
                        put("houseNumb", "房间号").
                        put("tenantName", "租客").
                        put("tenantTel", "租客电话").
                        put("billType", "账单类型").
                        put("billTime", "账单时间").
                        put("payState", "支付状态").
                        put("payTime", "支付时间").
                        put("total", "总额").
                        put("paySerial", "支付流水号").
                        put("remark", "备注")
                        .build();
        Map<String, Map> columnFormatMaps = new ImmutableMap.Builder<String, Map>()
                .put("billType", BillTypeCons.STRING_MAP)
                .put("payState", PayStateCons.STRING_MAP)
                .build();
        ExcelExport excelExport = new ExcelExport("账单记录", colums, "账单记录", rentBillList, columnFormatMaps);
        String fileName = DateTime.FULL_DATE_NOSPLIT.format(new Date()) + Strings.nullToEmpty(excelExport.getExcelTitle()) + ".xls";
        return FileDownUtil.downloadFile(ExcelUtil.export(excelExport), fileName);
    }
    /**
     * 手动增加账单
     *
     * @param bill
     * @return
     */
    @Override
    public Bill add(Bill bill) {
        if (bill != null && (bill.getId() == null || bill.getId() <= 0)) {
            bill.setBillTime(new Date());
            bill.setState(StatusCons.VALID);
            bill.setPayState(PayStateCons.UNPAYED);
            if(bill.getTotal()>=0)
            bill.setRefund(StatusCons.VALID);
            else  bill.setRefund(StatusCons.HISTORY);
            saveBill(bill);
        }
        Integer billType = bill.getBillType();
        if (billType.equals(BillTypeCons.RENTAL) || billType.equals(BillTypeCons.RENTAL) || billType.equals(BillTypeCons.RENTAL)) {
            //修改任务  以后可能会用到
        }
        return bill;
    }

    /**
     * 获取未支付账单总计
     *
     * @param billAttribution
     */
    @Override
    public BillTotal getTotalUnpayed(Long billAttribution) {
        Bill query = new Bill();
        query.setBillAttribution(billAttribution);
        query.setPayState(PayStateCons.UNPAYED);
        List<Bill> bills = billMapper.select(query);
        Float total = 0.00f;
        for (Bill bill : bills) {
            total += bill.getTotal();
        }
        return new BillTotal(String.valueOf(MathUtil.round(total)), bills);
    }


    /**
     * 客户端删除账单显示
     *
     * @param billId
     */
    @Override
    @Transactional
    public void updateState(Long billId) {
        Bill bill = new Bill();
        bill.setId(billId);
        bill.setState(BillClientStateCons.HIDDEN);
        billMapper.updateByPrimaryKeySelective(bill);
    }

    /**
     * 公寓管理员获取租客缴费信息及租房信息
     *
     * @param request
     * @return
     */
    @Override
    public PageResponse<List<RentBillCount>> getRentBillCountPage(PageRequest<RentBillCountQuery> request) {

        RentBillCountQuery query = request.getQuery();
        PageUtil.start(request);
        List<Rent> rents = billMapper.getEnterpriseRentInfo(query);
        PageResponse<List<RentBillCount>> response = PageUtil.getPageResponse(rents);
        List<RentBillCount> rentBillCounts = new ArrayList<>();
        rents.stream().forEach(rent -> {
            RentBillCount rentBillCount = new RentBillCount();
            //账单
            setRentBillCountBillState(rent.getId(), rentBillCount);
            //租客
            rentBillCount.setTenantId(rent.getTenantId());
            rentBillCount.setCardId(rent.getCardId());
            rentBillCount.setTenantName(rent.getTenantName());
            rentBillCount.setTenantTel(rent.getTenantTel());
            //房源
            rentBillCount.setHousesId(rent.getHousesId());
            rentBillCount.setCommunity(rent.getCommunity());
            rentBillCount.setHouseNumb(rent.getHouseNumb());
            StringBuilder sb = new StringBuilder("");
            if (Strings.isNullOrEmpty(rent.getAddress()))
                sb.append(rent.getAddress());
            if (Strings.isNullOrEmpty(rent.getBuilding()))
                sb.append(rent.getBuilding()).append("栋");
            if (Strings.isNullOrEmpty(rent.getUnit()))
                sb.append(rent.getUnit()).append("单元");
            if (Strings.isNullOrEmpty(rent.getHouseNumb()))
                sb.append(rent.getHouseNumb()).append("室");
            //租住状态
            rentBillCount.setRentId(rent.getId());
            rentBillCount.setRentState(rent.getState());
            rentBillCount.setRentStateName(RentStateCons.MAP.get(rent.getState()));
            rentBillCounts.add(rentBillCount);
        });
        response.setRows(rentBillCounts);
        return response;
    }

    /**
     * 公寓管理员获取租客缴费信息及租房信息
     * 设置账单状态
     *
     * @param rentId
     * @param rentBillCount
     */
    private void setRentBillCountBillState(Long rentId, RentBillCount rentBillCount) {
        BillTotal billTotal = getTotalUnpayed(rentId);
        rentBillCount.setBills(billTotal.getBills());
        if (billTotal.getBills() == null || billTotal.getBills().isEmpty()) {
            rentBillCount.setBillPayState("正常");
            rentBillCount.setArrearage("0.00");
            rentBillCount.setDelayDays(0L);
        } else {
            rentBillCount.setBillPayState("欠费");
            rentBillCount.setArrearage(billTotal.getTotal());
            LocalDate localDate = billTotal.getBills().get(0).getBillTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            LocalDate now = LocalDate.now();
            long daysDiff = ChronoUnit.DAYS.between(localDate, now);
            rentBillCount.setDelayDays(daysDiff);
        }
    }

    /**
     * 公寓管理员获取相关支付账单
     *
     * @param request
     * @return
     */
    @Override
    public PageResponse<List<Bill>> getEnterpriseBills(PageRequest<RentBillCountQuery> request) {
        PageUtil.start(request);
        return PageUtil.getPageResponse(billMapper.getEnterpriseBills(request.getQuery()));
    }

    /**
     * 财务月统计
     * 当月及上月数据
     *
     * @param enterpriseId
     * @return
     */
    @Override
    public BillMonthReport getEmployeeBillCountNow(Long enterpriseId) {
        String dateStr = getBalanceDateNow();
        EmployeeBillCountQuery query = new EmployeeBillCountQuery();
        query.setEnterpriseId(enterpriseId);
        query.setCountMonth(dateStr);
        BillMonthReport now;
        List<BillMonthReport> billMonthReports = billMapper.getEmployeeBillCount(query);
        if (billMonthReports == null || billMonthReports.isEmpty())
            now = new BillMonthReport();
        else now = billMonthReports.get(0);

        BillMonthReport nowE = billMapper.getMonthBaseExceptBill(query);
        if(nowE!=null)
        now.setMonthBaseExpect(nowE.getMonthBaseExpect());
        return now;
    }

    public Map getHomePageCnt(Long enterpriseId) {
        EmployeeBillCountQuery query = new EmployeeBillCountQuery();
        query.setEnterpriseId(enterpriseId);
        List<Map<String,Object>> list = billMapper.getHomePageCnt(query);
        Map<String,String> retMap = new HashMap<String,String>();
        int index = 1;
        for (Map<String,Object> map : list){
            String cnt = map.get("cnt")+"";
            retMap.put("cnt"+index,cnt);
            index++;
        }
        return retMap;
    }

    /**
     * 财务月统计
     * 分页查询含当前月
     *
     * @param request
     * @return
     */
    @Override
    public PageResponse<List<BillMonthReport>> getEmployeeBillCountPage(PageRequest<String> request) {
        String enterpriseId = request.getQuery();
        if (request.getNum() == 0 || request.getNum() == 1) {
            BillMonthReport now = getEmployeeBillCountNow(Long.valueOf(enterpriseId));
            if (request.getSize() == 1)
                return new PageResponse(now, 1L);
            request.setSize(request.getSize() - 1);
            PageUtil.start(request);
            List<BillMonthReport> list = billMonthReportMapper.selectOrderByMonthDesc(Long.valueOf(enterpriseId));
            PageResponse<List<BillMonthReport>> response = PageUtil.getPageResponse(list);
            response.setTotal(response.getTotal() + 1);
            response.setSize((long) Math.ceil(Double.valueOf(String.valueOf(response.getTotal() / (request.getSize() + 1)))));
            list.add(0, now);
            return response;
        } else {
            PageUtil.start(request);
            return PageUtil.getPageResponse(billMonthReportMapper.selectOrderByMonthDesc(Long.valueOf(enterpriseId)));
        }
    }

    /**
     * 每月1号生成上月财务月统计
     */
    @Override
    public void insertEmployeeBillCount() {
        EmployeeBillCountQuery query = new EmployeeBillCountQuery();
        query.setCountMonth(getBalanceDatePre());
        List<BillMonthReport> billMonthReports = billMapper.getEmployeeBillCount(query);
        billMonthReports.forEach(billMonthReport -> billMonthReportMapper.insert(billMonthReport));
    }


    /**
     * 结算押金
     *
     * @param rent
     * @return
     */
    @Override
    public Bill balanceDeposit(Rent rent) {
        Bill bill = new Bill();
        bill.setState(StatusCons.VALID);
        bill.setBillAttribution(rent.getId());
        bill.setBillType(BillTypeCons.DEPOSIT);
        bill.setPayState(PayStateCons.UNPAYED);
        bill.setBillTime(new Date());
        bill.setPrice(rent.getDeposit());
        bill.setTotal(rent.getDeposit());
        bill.setAbsoluteNumber(rent.getDeposit());
        saveBill(bill);
        return bill;
    }

    /**
     * 结算初始租金
     *
     * @param taskRegist
     * @return
     */
    @Override
    public Bill balanceInitRental(TaskRegist taskRegist) {
        Rent rent=taskRegist.getRent();
        Bill bill = new Bill();
        bill.setState(StatusCons.VALID);
        bill.setBillAttribution(rent.getId());
        bill.setBillType(BillTypeCons.RENTAL);
        bill.setPayState(PayStateCons.UNPAYED);
        bill.setBillTime(new Date());
        bill.setPrice(rent.getPriceSet());

        Integer cycle=taskRegist.getRentalBlanceCycle();
        if (cycle.equals(SetLeaseCons.MONTH))
            bill.setTotal(round(rent.getPriceSet()));
        else if (cycle.equals(SetLeaseCons.QUARTER))
            bill.setTotal(round(rent.getPriceSet() * 3));
        else if (cycle.equals(SetLeaseCons.HALF_YERA))
            bill.setTotal(round(rent.getPriceSet() * 6));
        else if (cycle.equals(SetLeaseCons.YERA))
            bill.setTotal(round(rent.getPriceSet() * 12));
        saveBill(bill);
        return bill;
    }

    /**
     * 结算押金和初始租金
     *
     * @param taskRegist
     */
    @Override
    public void balanceInitBill(TaskRegist taskRegist) {
        balanceDeposit(taskRegist.getRent());
        balanceInitRental(taskRegist);
        BalanceTask query = new BalanceTask();
        query.setBillAttribution(taskRegist.getRent().getId());
        query.setStatus(StatusCons.VALID);
        List<BalanceTask> tasks = balanceTaskService.query(query);
        tasks.stream().forEach(task -> {
            task.setHouseId(taskRegist.getRent().getHousesId());
            try {
                if (DateTime.SHORT_DATE.parse(task.getBalanceDate()).getTime() < DateTime.SHORT_DATE.parse(DateTime.SHORT_DATE.format(new Date())).getTime()) {
                    balance(task, false);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    public static final String FORMAT = "yyyy/MM";

    private String getBalanceDateNow() {
        LocalDate date = LocalDate.now();
        DateTimeFormatter df = DateTimeFormatter.ofPattern(FORMAT);
        return date.format(df);
    }

    private String getBalanceDatePre() {
        LocalDate date = LocalDate.now().minusMonths(1);
        DateTimeFormatter df = DateTimeFormatter.ofPattern(FORMAT);
        return date.format(df);
    }

    /**
     * 查询房间所有账单
     *
     * @param request
     * @return
     */
    @Override
    public PageResponse<List<Bill>> getBillListByHouseId(PageRequest<HousesBillQuery> request) {
        PageUtil.start(request);
        return PageUtil.getPageResponse(billMapper.getBillListByHouseId(request.getQuery()));
    }

    /**
     * 后台更新账单状态
     *
     * @param idArray
     */
    @Override
    @Transactional
    public void updatePayStateAndBillSate(Long[] idArray, String remark) {
        Arrays.stream(idArray).forEach(id -> {
            Bill bill = new Bill();
            bill.setId(id);
            bill.setPayState(PayStateCons.PAYED);
            bill.setPayTime(new Date());
            bill.setRemark(remark);
            billMapper.updateByPrimaryKeySelective(bill);
        });
    }

    /**
     * 结算账单 注销任务
     *
     * @param rentId
     */
    @Override
    public void balanceAllBills(Long rentId) {
        Bill bill = new Bill();
        bill.setPayState(PayStateCons.PAYED);
        bill.setPayTime(new Date());
        Example example = new Example(Bill.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("billAttribution",rentId).andEqualTo("payState",PayStateCons.UNPAYED);
        billMapper.updateByExampleSelective(bill,example);
        //balanceTaskService.unregistTask(rentId);//注销任务
    }

    /**
     * 获取租客所有已交未交总计
     *
     * @param rentId
     * @return
     */
    @Override
    public TenantBillFinalCount getTenantBillFinalCount(Long rentId) {
        TenantBillFinalCount count = billMapper.getTenantBillFinalCount(rentId);
        return count;
    }

    private Float round(Float money) {
        DecimalFormat decimalFormat = new DecimalFormat(".00");
        BigDecimal bigDecimal = new BigDecimal(money);
        return new Float(decimalFormat.format(bigDecimal));
    }

    /**
     * 按类别、时间统计账单支付总额
     *
     * @param
     */
    @Override
    public void saveBillCountByTypeModelList() {
        BillCountByTypeQuery query = new BillCountByTypeQuery();
        LocalDate now = LocalDate.now();
        query.setYear(now.getYear());
        query.setMonth(now.getMonthValue());
        billMapper.getBillCountByTypeModelList(query).forEach(v -> {
            v.setId(null);
            billCountByTypeMapper.insert(v);
        });
    }

    /**
     * 登录用户 按类别、时间统计账单支付总额
     *
     * @param query
     */
    @Override
    public BillCountByTypeModel getBillCountByTypeAndUserModel(BillCountByTypeQuery query) {
        List<BillCountByTypeModel> billCountByTypeModels = billMapper.getBillCountByTypeModelList(query);
        if (billCountByTypeModels != null && !billCountByTypeModels.isEmpty())
            return billCountByTypeModels.get(0);
        else return new BillCountByTypeModel(query);
    }

    /**
     * 登录用户 获取某年 按类别、月份统计账单支付总额
     *
     * @param query
     */
    @Override
    public List<BillCountByTypeModel> getBillCountByTypeAndUserModelListByYear(BillCountByTypeQuery query) {
        List<BillCountByTypeModel> list = billCountByTypeMapper.selectOrderByMonthDesc(query);
        query.setMonth(LocalDate.now().getMonthValue());
        BillCountByTypeModel billCountByTypeModel = getBillCountByTypeAndUserModel(query);
        if (list == null) list = new ArrayList<>();
        else if (list.isEmpty())
            list.add(billCountByTypeModel);
        else {
            list.add(0, billCountByTypeModel);
        }
        return list;
    }
}
